﻿/// ISP Visual Studio Plug-in
/// Authors: Michael DeLisi + Geof Sawaya
/// IspPackage.cs: Main entry point in to the Visual Studio package, and
///                functions to handle the GUI toolbar interactions.

using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.ComponentModel.Design;
using Microsoft.Win32;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;
using System.Windows.Forms;
using EnvDTE;
using Thread = System.Threading.Thread;
using Process = System.Diagnostics.Process;
using System.IO;
using EnvDTE80;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using Microsoft.VisualStudio.VCProjectEngine;
using System.Text;

namespace Gauss.Isp
{
    /// <summary>
    /// This is the class that implements the package exposed by this assembly.
    /// </summary>
    // This attribute tells the registration utility (regpkg.exe) that this class needs
    // to be registered as package.
    [PackageRegistration(UseManagedResourcesOnly = true)]
    // A Visual Studio component can be registered under different regitry roots; for instance
    // when you debug your package you want to register it in the experimental hive. This
    // attribute specifies the registry root to use if no one is provided to regpkg.exe with
    // the /root switch.
    //[DefaultRegistryRoot("Software\\Microsoft\\VisualStudio\\9.0")]
    //above removed per http://msdn.microsoft.com/en-us/library/cc512930.aspx
    // This attribute is used to register the informations needed to show the this package
    // in the Help/About dialog of Visual Studio.
    [InstalledProductRegistration("#110", "#112", "0.3.0", IconResourceID = 400)]
    // In order be loaded inside Visual Studio in a machine that has not the VS SDK installed, 
    // package needs to have a valid load key (it can be requested at 
    // http://msdn.microsoft.com/vstudio/extend/). This attributes tells the shell that this 
    // package has a load key embedded in its resources.
    [ProvideLoadKey("Standard", "0.3.0", "ISP", "University of Utah, School of Computing", 1)]
    // This attribute is needed to let the shell know that this package exposes some menus.
    [ProvideMenuResource(1000, 1)]
    // This attribute registers a tool window exposed by this package.
    [ProvideToolWindow(typeof(DebuggerToolWindow), Style = Microsoft.VisualStudio.Shell.VsDockStyle.Float, Window = "3ae79031-e1bc-11d0-8f78-00a0c9110057")]
    // This attribute registers the Tools -> Options pane exposed by this package.
    [ProvideOptionPage(typeof(ToolsOptions), "ISP", "General", 2, 3, true)]
    [Guid(GuidList.guidISPPkgString)]
    public sealed class IspPackage : Package
    {
        #region Member Variables

        private SolutionEvents _solutionEvents;
        private OleMenuCommand _toolbarButton_RunIsp;
        private MenuCommand _toolbarButton_Configuration;
        private MenuCommand _toolbarButton_JavaGui;
        private MenuCommand _toolbarButton_SourceAnalyzer;
        private OleMenuCommand _toolbarButton_Status;
        private DTE2 _dte;
        private int _numberProcesses;
        private string[] _numberProcessesChoices;
        private IspChecker _isp;
        private Thread _ispThread, _sourceThread, _javaThread, _debuggerThread;
        private enum ButtonState { NoProjectOpened, NotRunIsp, RunningIsp, RanIsp, RunningJavaGui, RunningSourceAnalyzer }
        private ToolWindowPane _debuggerToolWindow;

        #endregion

        #region Initialization

        /// <summary>
        /// This does the initialization that does not require any Visual Studio services,
        /// because at this point the package object is created but not sited yet inside
        /// Visual Studio environment. The place to do all the other initialization is
        /// the Initialize method.
        /// </summary>
        public IspPackage()
        {
            // The default "Number Processes" value on the toolbar.
            _numberProcesses = 2;

            // The entries for the "Number Processes" dropdown.
            _numberProcessesChoices = new string[39];
            for (int i = 0; i < _numberProcessesChoices.Length; i++)
                _numberProcessesChoices[i] = (i+2).ToString();
        }

        /// <summary>
        /// Initialization of the package; this initializes all of the commands on the
        /// toolbar.
        /// </summary>
        protected override void Initialize()
        {
            base.Initialize();

            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledException);

            // Add our command handlers for menu (commands must exist in the .vsct file)
            OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
            if ( null != mcs )
            {
                // Initialize the "Run ISP" button.
                CommandID runIspCommandID = new CommandID(GuidList.guidISPCmdSet, (int)PkgCmdIDList.cmdidRunISP);
                _toolbarButton_RunIsp = new OleMenuCommand(new EventHandler(RunISP_Click), runIspCommandID);
                mcs.AddCommand(_toolbarButton_RunIsp);

                // Initialize the "Number Processes" combo box.
                CommandID numberProcessesCommandID = new CommandID(GuidList.guidISPCmdSet, (int)PkgCmdIDList.cmdidNumberProcesses);
                OleMenuCommand numberProcessesItem = new OleMenuCommand(new EventHandler(NumberProcesses_Changed), numberProcessesCommandID);
                numberProcessesItem.ParametersDescription = "$";
                mcs.AddCommand(numberProcessesItem);

                // Initialize the "Number Processes" dropdown list.
                CommandID numberProcessesGetListCommandID = new CommandID(GuidList.guidISPCmdSet, (int)PkgCmdIDList.cmdidNumberProcessesGetList);
                MenuCommand numberProcessesGetListItem = new OleMenuCommand(new EventHandler(NumberProcesses_List), numberProcessesGetListCommandID);
                mcs.AddCommand(numberProcessesGetListItem);

                // Initialize the "Configuration" button.
                CommandID configurationCommandID = new CommandID(GuidList.guidISPCmdSet, (int)PkgCmdIDList.cmdidConfiguration);
                _toolbarButton_Configuration = new MenuCommand(Configuration_Click, configurationCommandID);
                mcs.AddCommand(_toolbarButton_Configuration);

                // Initialize the "Source Analyzer" button.
                CommandID sourceAnalyzerCommandID = new CommandID(GuidList.guidISPCmdSet, (int)PkgCmdIDList.cmdidSourceAnalyzer);
                _toolbarButton_SourceAnalyzer = new MenuCommand(SourceAnalyzer_Click, sourceAnalyzerCommandID);
                mcs.AddCommand(_toolbarButton_SourceAnalyzer);

                // Initialize the "Java GUI" button.
                CommandID javaGuiCommandID = new CommandID(GuidList.guidISPCmdSet, (int)PkgCmdIDList.cmdidJavaGUI);
                _toolbarButton_JavaGui = new MenuCommand(JavaGUI_Click, javaGuiCommandID);
                mcs.AddCommand(_toolbarButton_JavaGui);

                // Initialize the "Status" display.
                CommandID statusDisplayCommandID = new CommandID(GuidList.guidISPCmdSet, (int)PkgCmdIDList.cmdidStatusDisplay);
                _toolbarButton_Status = new OleMenuCommand(new EventHandler(IspStatusDisplay_Click), statusDisplayCommandID);
                mcs.AddCommand(_toolbarButton_Status);
            }

            // The DTE object is needed for lots of things, so create it now and just reference it later.
            _dte = GetService(typeof(SDTE)) as DTE2;
            if (_dte == null)
            {
                throw new ApplicationException(Resources.Message_CannotAccessDTE);
            }

            // This is the object that allows you to access the ISP interface. It is used in many of the
            // GUI functions below, so create it now and store it for later.
            _isp = new IspChecker(GetDialogPage(typeof(ToolsOptions)) as ToolsOptions, _dte);

            // Setup events to determine when a solution is opened and closed, so the number of processes
            // can be saved and loaded for the individual solution.
            _solutionEvents = _dte.Events.SolutionEvents;
            _solutionEvents.Opened += new _dispSolutionEvents_OpenedEventHandler(SolutionOpened);
            _solutionEvents.AfterClosing += new _dispSolutionEvents_AfterClosingEventHandler(SolutionClosed);
            if (_dte.Solution.Count > 0)
            {
                SolutionOpened();
            }
            else
            {
                SolutionClosed();
            }
        }

        private void UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Exception exception = e.ExceptionObject as Exception;
            if (exception != null)
            {
                Utils.MessageBox(exception, Utils.StringFormat(Resources.UnhandledException, exception.Message));
            }
        }

        #endregion

        #region Solution Event Handlers

        /// <summary>
        /// This function is called when a solution is opened. It loads the number of processes
        /// from the solution file, and updates the text in the toolbar. It also enables the
        /// appropriate buttons on the toolbar so it is functional.
        /// </summary>
        private void SolutionOpened()
        {
            try
            {
                if (_dte.Solution.Globals.get_VariablePersists("IspNumberProcesses"))
                    Utils.TryParseInt(_dte.Solution.Globals["IspNumberProcesses"].ToString(), out _numberProcesses);
            }
            catch { }
            SetButtons(ButtonState.NotRunIsp);
        }

        /// <summary>
        /// This function is called when a solution is closed. It disables the toolbar buttons.
        /// </summary>
        private void SolutionClosed()
        {
            SetButtons(ButtonState.NoProjectOpened);
            _isp.RemoveLogFile();
        }

        #endregion

        #region Toolbar Event Handlers

        /// <summary>
        /// This is the event handler that is called when the "Run ISP" button is clicked.
        /// It will recompile the indicated projects and link against ISP. It will then run
        /// ISP and update the GUI with the results.
        /// </summary>
        private void RunISP_Click(object sender, EventArgs e)
        {
            if (_ispThread != null && _ispThread.IsAlive)
            {
                _toolbarButton_RunIsp.Enabled = false;
                _ispThread.Abort();
                return;
            }

            ToolsOptions options = GetDialogPage(typeof(ToolsOptions)) as ToolsOptions;
            if (options == null)
            {
                Utils.MessageBox(null, Resources.Message_IspOptionsDialogNotLoaded, MessageBoxIcon.Error);
                return;
            }
            if (options.ShowIspCompileDialog)
            {
                DialogResult result = Utils.MessageBox(null, Resources.Message_RunningIspWarningMessage, null, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                if (result == DialogResult.No)
                {
                    return;
                }
            }

            SetButtons(ButtonState.RunningIsp);

            _ispThread = new Thread(
                delegate()
                {
                    try
                    {
                        // Turn on the status bar animations.
                        try
                        {
                            _dte.StatusBar.Animate(true, vsStatusAnimation.vsStatusAnimationGeneral);
                        }
                        catch { }

                        // Remove the old log file if one exists.
                        _isp.RemoveLogFile();

                        // Launch ISP.
                        _isp.Run(_numberProcesses);
                    }
                    catch (ThreadAbortException)
                    {
                    }
                    catch (Exception ex)
                    {
                        Utils.MessageBox(ex, Utils.StringFormat("{0}\n{1}", Resources.Message_ErrorRunningIsp, ex.Message), MessageBoxIcon.Error);
                    }
                    finally
                    {
                        // Turn off the status bar animations
                        try
                        {
                            _dte.StatusBar.Animate(false, vsStatusAnimation.vsStatusAnimationGeneral);
                        }
                        catch { }

                        // Re-enable the buttons.
                        if (_isp.HasRun)
                        {
                            SetButtons(ButtonState.RanIsp);
                        }
                        else
                        {
                            SetButtons(ButtonState.NotRunIsp);
                        }
                    }
                });
            _ispThread.Start();
        }

        /// <summary>
        /// This is the event handler that gets called when the number of processes input
        /// field has changed, or the input field needs updating.
        /// </summary>
        private void NumberProcesses_Changed(object sender, EventArgs e)
        {
            if (e == null || e == EventArgs.Empty)
            {
                return;
            }
            OleMenuCmdEventArgs eventArgs = e as OleMenuCmdEventArgs;
            if (eventArgs == null)
            {
                return;
            }

            string newChoice = eventArgs.InValue as string;
            IntPtr vOut = eventArgs.OutValue;
            if (vOut != IntPtr.Zero && newChoice != null)
            {
                return;
            }
            else if (vOut != IntPtr.Zero)
            {
                // The IDE is requesting the current value for the combo.
                string procs = _numberProcesses.ToString();
                Marshal.GetNativeVariantForObject(procs, vOut);
            }
            else if (newChoice != null)
            {
                // New value was selected or typed in, check if it is a valid input
                int result;
                if (Utils.TryParseInt(newChoice, out result) && result >= 2)
                {
                    // A correct value was given.
                    SetNewNumberProcessesValue(result);
                }
                else
                {
                    // An invalid input has been specified
                    Utils.MessageBox(null, Resources.Message_NumberProcessesInvalid, MessageBoxIcon.Information);
                    return;
                }
            }
            else
            {
                // We should never get here
                return;
            }
        }

        /// <summary>
        /// This is the event handler for when the "Number Processes" drop down needs to
        /// be populated.
        /// </summary>
        private void NumberProcesses_List(object sender, EventArgs e)
        {
            if (e == null || e == EventArgs.Empty)
            {
                return;
            }
            OleMenuCmdEventArgs eventArgs = e as OleMenuCmdEventArgs;
            if (eventArgs != null)
            {
                object inParam = eventArgs.InValue;
                IntPtr vOut = eventArgs.OutValue;
                if (inParam != null)
                {
                    return;
                }
                else if (vOut != IntPtr.Zero)
                {
                    Marshal.GetNativeVariantForObject(_numberProcessesChoices, vOut);
                }
                else
                {
                    return;
                }
            }
        }

        /// <summary>
        /// This is the event handler for when the "Configuration" button is clicked.
        /// </summary>
        private void Configuration_Click(object sender, EventArgs e)
        {
            try
            {
                ConfigurationDialog config = new ConfigurationDialog(_dte.Solution);
                config.NumberProcesses = _numberProcesses;
                config.ShowDialog();
                SetNewNumberProcessesValue(config.NumberProcesses);
            }
            catch (Exception ex)
            {
                Utils.MessageBox(ex, Utils.StringFormat("{0}\n{1}", Resources.Message_ErrorRunningIspConfiguration, ex.Message));
            }
        }

        /// <summary>
        /// This event handler is called when the "Source Analyzer" button is clicked. It will
        /// load the GUI with the most recently generated log file.
        /// </summary>
        private void SourceAnalyzer_Click(object sender, EventArgs e)
        {
            if (_sourceThread != null && _sourceThread.IsAlive)
            {
                Utils.MessageBox(null, Resources.SourceAnalyzer_InUse, MessageBoxIcon.Warning);
                return;
            }

            if (!_isp.HasRun)
            {
                Utils.MessageBox(null, Resources.Message_NoLogFile, MessageBoxIcon.Information);
                return;
            }

            ToolsOptions options = GetDialogPage(typeof(ToolsOptions)) as ToolsOptions;
            if (options == null)
            {
                Utils.MessageBox(null, Resources.Message_IspOptionsDialogNotLoaded, MessageBoxIcon.Error);
                return;
            }

            if (_debuggerToolWindow == null)
            {
                _debuggerToolWindow = FindToolWindow(typeof(DebuggerToolWindow), 0, true);
            }

            SetButtons(ButtonState.RunningSourceAnalyzer);

            _sourceThread = new Thread(
                delegate()
                {
                    try
                    {
                        IspStepperGui gui = new IspStepperGui(_isp.LogFile, options.UseIssueOrder);

                        //gui.Show();
                        gui.ShowDialog();

                        // Did the user request the debugger to be started?
                        if (gui.DebugProject)
                        {
                            // If the debugger is already started, we cannot launch.
                            if (_dte.Debugger.CurrentMode != dbgDebugMode.dbgDesignMode)
                            {
                                Utils.MessageBox(null, "The debugger could not be started, because it is already in use.", MessageBoxIcon.Warning);
                                return;
                            }

                            // If there is a previous thread, kill it.
                            if (_debuggerThread != null && _debuggerThread.IsAlive)
                            {
                                _debuggerThread.Abort();
                                _debuggerThread.Join();
                            }

                            // Start the debugger thread.
                            _debuggerThread = new Thread(
                                delegate()
                                {
                                    try
                                    {
                                        //TODO: This probably will have problems due to creating GUI on a different thread
                                        //than the VS GUI thread
                                        Debugger debugger = new Debugger(gui.DebugInterleaving, gui.DebugTransition,
                                                                         _isp.NumberProcesses, _isp.ProjectsList, _dte,
                                                                         GetDialogPage(typeof(ToolsOptions)) as ToolsOptions,
                                                                         _debuggerToolWindow as DebuggerToolWindow);
                                        debugger.Start();
                                    }
                                    catch (ThreadAbortException)
                                    {
                                        return;
                                    }
                                    catch (Exception ex)
                                    {
                                        Utils.MessageBox(ex, "There was an error when debugging the application: " + ex.Message);
                                    }
                                });
                            _debuggerThread.Start();
                        }
                    }
                    catch (FileNotFoundException ex)
                    {
                        Utils.MessageBox(ex, Utils.StringFormat(Resources.SourceAnalyzer_FileNotFound, _isp.LogFile), MessageBoxIcon.Error);
                        _isp.RemoveLogFile();
                    }
                    catch (NoMpiCallException ex)
                    {
                        Utils.MessageBox(ex, Resources.SourceAnalyzer_NoCalls, MessageBoxIcon.Information);
                    }
                    catch (Exception ex)
                    {
                        Utils.MessageBox(ex, Utils.StringFormat(Resources.Message_ErrorRunningSourceAnalyzer, ex.Message), MessageBoxIcon.Error);
                    }
                    finally
                    {
                        _sourceThread = null;
                        if (_isp.HasRun)
                            SetButtons(ButtonState.RanIsp);
                        else
                            SetButtons(ButtonState.NotRunIsp);
                    }
                });
            _sourceThread.SetApartmentState(ApartmentState.STA);
            _sourceThread.Start();
        }

        /// <summary>
        /// This event handler is called when the "Java GUI" button is clicked. It will
        /// load the Java GUI with the most recently generated log file.
        /// </summary>
        private void JavaGUI_Click(object sender, EventArgs e)
        {
            if (_javaThread != null && _javaThread.IsAlive)
            {
                Utils.MessageBox(null, Resources.Message_JavaGuiInUse, MessageBoxIcon.Warning);
                return;
            }

            if (!_isp.HasRun)
            {
                Utils.MessageBox(null, Resources.Message_NoLogFile, MessageBoxIcon.Information);
                return;
            }

            ToolsOptions options = GetDialogPage(typeof(ToolsOptions)) as ToolsOptions;
            if (options == null)
            {
                Utils.MessageBox(null, Resources.Message_IspOptionsDialogNotLoaded, MessageBoxIcon.Error);
                return;
            }

            FileInfo ispUiPath = options.Get_IspUiPath;
            if (ispUiPath == null)
            {
                Utils.MessageBox(null, Utils.StringFormat(Resources.Message_CannotFindFile, "ispui.jar"), MessageBoxIcon.Error);
                return;
            }

            SetButtons(ButtonState.RunningJavaGui);

            _javaThread = new Thread(
                delegate()
                {
                    try
                    {
                        try
                        {
                            using (Process process = new Process())
                            {
                                process.StartInfo.FileName = options.Get_JavaPath;
                                process.StartInfo.Arguments = Utils.StringFormat("-Xmx256m -jar \"{0}\" \"{1}\"", ispUiPath.FullName, _isp.LogFile);
                                process.StartInfo.RedirectStandardError = false;
                                process.StartInfo.RedirectStandardOutput = false;
                                process.StartInfo.RedirectStandardInput = false;
                                process.StartInfo.CreateNoWindow = true;
                                process.StartInfo.UseShellExecute = false;
                                process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
                                process.StartInfo.WorkingDirectory = Path.GetTempPath();
                                process.Start();
                                process.WaitForExit(int.MaxValue - 1);
                            }
                        }
                        catch (System.ComponentModel.Win32Exception ex)
                        {
                            if (ex.NativeErrorCode == 2)
                            {
                                Utils.MessageBox(ex, Utils.StringFormat(Resources.Message_CannotFindFile, "java.exe"), MessageBoxIcon.Error);
                            }
                            else
                            {
                                throw;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Utils.MessageBox(ex, Utils.StringFormat("{0}\n{1}", Resources.Message_ErrorRunningJavaGui, ex.Message));
                    }
                    finally
                    {
                        _javaThread = null;
                        SetButtons(ButtonState.RanIsp);
                    }
                });
            _javaThread.Start();
        }

        /// <summary>
        /// This event handler will be called when the "Status" button is clicked on the
        /// ISP toolbar.
        /// </summary>
        private void IspStatusDisplay_Click(object sender, EventArgs e)
        {
            string message = null;
            if (_isp.IsRunning)
            {
                message = Utils.StringFormat("{0}\n\n{1}",
                                        Utils.StringFormat(Resources.IspStatus_IspRunning, _isp.NumberProcesses),
                                        Utils.StringFormat(Resources.IspStatus_Stats_Running, _isp.NumberInterleavings, _isp.ElapsedTime));
            }
            else if (_isp.HasRun)
            {
                switch (_isp.ExitCode)
                {
                    case 0:
                        message = Utils.StringFormat("{0}\n\n{1}",
                                        Utils.StringFormat(Resources.IspStatus_NoDeadlocks, _isp.NumberProcesses),
                                        Utils.StringFormat(Resources.IspStatus_Stats, _isp.NumberInterleavings, _isp.ElapsedTime));
                        break;
                    case 1:
                        message = Utils.StringFormat("{0}\n\n{1}",
                                        Utils.StringFormat(Resources.IspStatus_Deadlock, _isp.NumberProcesses),
                                        Utils.StringFormat(Resources.IspStatus_Stats, _isp.NumberInterleavings, _isp.ElapsedTime));
                        break;
                    case 3:
                        message = Utils.StringFormat("{0}\n\n{1}",
                                        Utils.StringFormat(Resources.IspStatus_AssertionViolation, _isp.NumberProcesses),
                                        Utils.StringFormat(Resources.IspStatus_Stats, _isp.NumberInterleavings, _isp.ElapsedTime));
                        break;
                    default:
                        message = Utils.StringFormat("{0}\n\n{1}",
                                        Utils.StringFormat(Resources.IspStatus_UnknownError, _isp.NumberProcesses, _isp.ExitCode, _isp.ExitCodeString),
                                        Utils.StringFormat(Resources.IspStatus_Stats, _isp.NumberInterleavings, _isp.ElapsedTime));
                        break;
                }
            }
            else
            {
                message = Resources.IspStatus_NotRun;
            }

            if (message != null)
            {
                Utils.MessageBox(null, message, MessageBoxIcon.Information);
            }
        }

        #endregion

        #region Helper Functions

        /// <summary>
        /// This is a helper function that sets up the toolbar buttons, depending on the given
        /// state of the solution.
        /// </summary>
        /// <param name="state">The solution's state.</param>
        private void SetButtons(ButtonState state)
        {
            switch (state)
            {
                case ButtonState.NotRunIsp:
                    _toolbarButton_RunIsp.Enabled = true;
                    _toolbarButton_RunIsp.Text = "Run ISP";
                    _toolbarButton_Configuration.Enabled = true;
                    _toolbarButton_JavaGui.Enabled = false;
                    _toolbarButton_SourceAnalyzer.Enabled = false;
                    _toolbarButton_Status.Text = Resources.IspShortStatus_NotRun;
                    break;
                case ButtonState.RanIsp:
                    _toolbarButton_RunIsp.Enabled = true;
                    _toolbarButton_RunIsp.Text = "Run ISP";
                    _toolbarButton_Configuration.Enabled = true;
                    _toolbarButton_JavaGui.Enabled = _javaThread == null || (_javaThread != null && !_javaThread.IsAlive);
                    _toolbarButton_SourceAnalyzer.Enabled = _sourceThread == null || (_sourceThread != null && !_sourceThread.IsAlive);
                    if (_sourceThread != null && _sourceThread.IsAlive)
                        _toolbarButton_Status.Text = Resources.IspShortStatus_SourceAnalyzerRunning;
                    else if (_javaThread != null && _javaThread.IsAlive)
                        _toolbarButton_Status.Text = Resources.IspShortStatus_JavaGuiRunning;
                    else if (_isp.ExitCode == 1)
                        _toolbarButton_Status.Text = Resources.IspShortStatus_Deadlock;
                    else if (_isp.ExitCode == 3)
                        _toolbarButton_Status.Text = Resources.IspShortStatus_AssertionViolation;
                    else if (_isp.ExitCode == 4)
                        _toolbarButton_Status.Text = Resources.IspShortStatus_Abort;
                    else if (_isp.ExitCode == 5)
                        _toolbarButton_Status.Text = Resources.IspShortStatus_InvalidRank;
                    else if (_isp.ExitCode == 0)
                        _toolbarButton_Status.Text = Resources.IspShortStatus_NoDeadlocks;
                    else
                        _toolbarButton_Status.Text = Resources.IspShortStatus_Error;
                    break;
                case ButtonState.NoProjectOpened:
                    _toolbarButton_RunIsp.Enabled = false;
                    _toolbarButton_RunIsp.Text = "Run ISP";
                    _toolbarButton_Configuration.Enabled = false;
                    _toolbarButton_JavaGui.Enabled = false;
                    _toolbarButton_SourceAnalyzer.Enabled = false;
                    _toolbarButton_Status.Text = Resources.IspShortStatus_NoProjects;
                    break;
                case ButtonState.RunningIsp:
                    _toolbarButton_RunIsp.Enabled = true;
                    _toolbarButton_RunIsp.Text = "Stop ISP";
                    _toolbarButton_Configuration.Enabled = false;
                    _toolbarButton_JavaGui.Enabled = false;
                    _toolbarButton_SourceAnalyzer.Enabled = false;
                    _toolbarButton_Status.Text = Resources.IspShortStatus_IspRunning;
                    break;
                case ButtonState.RunningJavaGui:
                    _toolbarButton_RunIsp.Enabled = false;
                    _toolbarButton_RunIsp.Text = "Run ISP";
                    _toolbarButton_Configuration.Enabled = true;
                    _toolbarButton_JavaGui.Enabled = false;
                    _toolbarButton_SourceAnalyzer.Enabled = _sourceThread == null || (_sourceThread != null && !_sourceThread.IsAlive);
                    _toolbarButton_Status.Text = Resources.IspShortStatus_JavaGuiRunning;
                    break;
                case ButtonState.RunningSourceAnalyzer:
                    _toolbarButton_RunIsp.Enabled = false;
                    _toolbarButton_RunIsp.Text = "Run ISP";
                    _toolbarButton_Configuration.Enabled = true;
                    _toolbarButton_JavaGui.Enabled = _javaThread == null || (_javaThread != null && !_javaThread.IsAlive);
                    _toolbarButton_SourceAnalyzer.Enabled = false;
                    _toolbarButton_Status.Text = Resources.IspShortStatus_SourceAnalyzerRunning;
                    break;
            }
        }

        /// <summary>
        /// Helper function that takes the input and stores it to the solution file for
        /// later retreval. The new value will be updated in the toolbar also.
        /// </summary>
        /// <param name="val">The new number of processes.</param>
        private void SetNewNumberProcessesValue(int val)
        {
            if (val != _numberProcesses)
            {
                try
                {
                    _numberProcesses = val;
                    if (_dte.Solution.Count > 0)
                    {
                        _dte.Solution.Globals["IspNumberProcesses"] = val;
                        _dte.Solution.Globals.set_VariablePersists("IspNumberProcesses", true);
                    }
                }
                catch { }
            }
        }

        #endregion

        #region Dispose

        /// <summary>
        /// This deletes ISP's log file if one exists, and removes the added event handlers.
        /// </summary>
        /// <param name="disposing"></param>
        protected override void Dispose(bool disposing)
        {
            _isp.RemoveLogFile();
            _solutionEvents.Opened -= new _dispSolutionEvents_OpenedEventHandler(SolutionOpened);
            _solutionEvents.AfterClosing -= new _dispSolutionEvents_AfterClosingEventHandler(SolutionClosed);

            base.Dispose(disposing);
        }

        #endregion

    }
}